﻿#include <iostream>
#include <winsock2.h>
#include <thread>
#include <atomic>
#include <string>
#include <map>
#include <mutex>
#include <chrono>
#include <vector>
#pragma comment(lib, "ws2_32.lib")

std::atomic<bool> running(true);
const std::string ROUTER_ID = "192.168.2.1";

struct RouteEntry {
    std::string destination;
    std::string nextHop;
    int hops;
    std::chrono::steady_clock::time_point timestamp;
};

std::mutex tableMutex;
std::map<std::string, RouteEntry> routeTable;

void sender_thread(SOCKET sock) {
    while (running) {
        std::string message = "RIP_UPDATE;" + ROUTER_ID;
        {
            std::lock_guard<std::mutex> lock(tableMutex);
            for (const auto& entry : routeTable) {
                if (entry.second.hops < 16) {
                    message += ";" + entry.second.destination + "," + std::to_string(entry.second.hops);
                }
            }
        }
        send(sock, message.c_str(), static_cast<int>(message.size()), 0);
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
}

void receiver_thread(SOCKET sock) {
    char buffer[1024];
    while (running) {
        int bytesReceived = recv(sock, buffer, sizeof(buffer), 0);
        if (bytesReceived > 0) {
            buffer[bytesReceived] = '\0';
            std::string receivedMsg(buffer);

            if (receivedMsg.find("RIP_UPDATE;") == 0) {
                size_t pos1 = strlen("RIP_UPDATE;");
                size_t pos2 = receivedMsg.find(';', pos1);
                if (pos2 == std::string::npos) continue;

                std::string sourceAddress = receivedMsg.substr(pos1, pos2 - pos1);
                std::string entriesStr = receivedMsg.substr(pos2 + 1);

                std::vector<std::string> entries;
                size_t start = 0;
                size_t end;
                while ((end = entriesStr.find(';', start)) != std::string::npos) {
                    entries.push_back(entriesStr.substr(start, end - start));
                    start = end + 1;
                }
                entries.push_back(entriesStr.substr(start));

                for (const auto& entry : entries) {
                    size_t commaPos = entry.find(',');
                    if (commaPos != std::string::npos) {
                        std::string dest = entry.substr(0, commaPos);
                        std::string hopsStr = entry.substr(commaPos + 1);
                        try {
                            int receivedHops = std::stoi(hopsStr);
                            int newHops = receivedHops + 1;

                            if (newHops > 15) continue;

                            std::lock_guard<std::mutex> lock(tableMutex);
                            auto it = routeTable.find(dest);
                            if (it != routeTable.end()) {
                                if (newHops < it->second.hops || 
                                    (it->second.nextHop == sourceAddress && newHops != it->second.hops)) {
                                    it->second.hops = newHops;
                                    it->second.nextHop = sourceAddress;
                                    it->second.timestamp = std::chrono::steady_clock::now();
                                }
                            } else {
                                routeTable[dest] = { dest, sourceAddress, newHops, 
                                    std::chrono::steady_clock::now() };
                            }
                        } catch (...) {}
                    }
                }
            }
        }
        else if (bytesReceived <= 0) {
            running = false;
            break;
        }
    }
}

void timer_thread() {
    constexpr int AGING_TIME = 10;
    while (running) {
        std::this_thread::sleep_for(std::chrono::seconds(5));

        auto now = std::chrono::steady_clock::now();
        std::lock_guard<std::mutex> lock(tableMutex);

        auto it = routeTable.begin();
        while (it != routeTable.end()) {
            auto age = std::chrono::duration_cast<std::chrono::seconds>(
                now - it->second.timestamp).count();
            if (age > AGING_TIME) {
                it = routeTable.erase(it);
            } else {
                ++it;
            }
        }

        std::cout << "\n当前路由表 (" << routeTable.size() << " 条目):" << std::endl;
        for (const auto& entry : routeTable) {
            auto age = std::chrono::duration_cast<std::chrono::seconds>(
                now - entry.second.timestamp).count();
            std::cout << "  目标网络: " << entry.second.destination
                      << " | 下一跳: " << entry.second.nextHop
                      << " | 跳数: " << entry.second.hops
                      << " | 年龄: " << age << "秒" << std::endl;
        }
        std::cout << std::endl;
    }
}

int main() {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    {
        std::lock_guard<std::mutex> lock(tableMutex);
        routeTable["192.168.2.0"] = { "192.168.2.0", "0.0.0.0", 0, 
            std::chrono::steady_clock::now() };
    }

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8080);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
    listen(serverSocket, 5);

    std::cout << "服务器启动，监听端口8080...\n";

    SOCKET clientSocket;
    sockaddr_in clientAddr;
    int clientAddrSize = sizeof(clientAddr);
    clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
    std::cout << "客户端连接成功!\n";

    std::thread timer(timer_thread);
    timer.detach();

    std::thread sender(sender_thread, clientSocket);
    std::thread receiver(receiver_thread, clientSocket);

    sender.join();
    receiver.join();

    closesocket(clientSocket);
    closesocket(serverSocket);
    WSACleanup();
    return 0;
}